/*
 * Powered By XY
 * Since 2020
 */

package com.xy.biz.xd.service.impl;

import com.xy.biz.base.client.DictClient;
import com.xy.biz.base.domain.constant.DictCodeConstant;
import com.xy.biz.base.domain.dto.DictDTO;
import com.xy.biz.base.domain.req.GetDictByCodeRequest;
import com.xy.biz.base.domain.req.GetDictRequest;
import com.xy.biz.base.domain.resp.ListDictItemResponse;
import com.xy.biz.fd.client.DocumentClient;
import com.xy.biz.fd.client.DocumentCodeRuleClient;
import com.xy.biz.fd.domain.req.document.GetDocumentRequest;
import com.xy.biz.fd.domain.req.documentCode.GetDocumentByCodeRequest;
import com.xy.biz.fd.domain.resp.GetDocumentResponse;
import com.xy.biz.uc.client.UserClient;
import com.xy.biz.uc.client.UserGroupClient;
import com.xy.biz.uc.domain.dto.UserDTO;
import com.xy.biz.uc.domain.dto.UserGroupDTO;
import com.xy.biz.uc.domain.req.GetUserGroupRequest;
import com.xy.biz.uc.domain.req.ListUserGroupByIdsRequest;
import com.xy.biz.xd.domain.bo.DocumentFlowBO;
import com.xy.biz.xd.domain.bo.DocumentFlowConstants;
import com.xy.biz.xd.domain.bo.DocumentFlowHandleBO;
import com.xy.biz.xd.domain.bo.DocumentFlowNewAndModifyBO;
import com.xy.biz.xd.domain.converter.DocumentFlowConverter;
import com.xy.biz.xd.domain.converter.DocumentFlowHandleConverter;
import com.xy.biz.xd.domain.enums.DocumentFlowBatchTypeEnum;
import com.xy.biz.xd.domain.query.DocumentFlowHandleQuery;
import com.xy.biz.xd.domain.query.DocumentFlowQuery;
import com.xy.biz.xd.domain.req.GetDocumentFlowSimpleHandlesRequest;
import com.xy.biz.xd.domain.resp.DocumentFlowHandleTimeLineResponse;
import com.xy.biz.xd.domain.resp.GetDocumentFlowHandleResponse;
import com.xy.biz.xd.domain.resp.GetDocumentFlowResponse;
import com.xy.biz.xd.domain.tree.UserTreeItem;
import com.xy.biz.xd.manager.DocumentFlowHandleManager;
import com.xy.biz.xd.manager.DocumentFlowManager;
import com.xy.biz.xd.manager.DocumentFlowNewAndModifyManager;
import com.xy.biz.xd.service.DocumentFlowHandleService;
import com.xy.lang.domain.Result;
import com.xy.lang.domain.treeing.TreeItem;
import com.xy.lang.util.CalendarUtils;
import com.xy.lang.util.ResultUtils;
import com.xy.tool.context.UserContextHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

import static com.xy.biz.xd.domain.bo.DocumentFlowConstants.HANDLE_RESULT_CANCEL;

/**
 * @author wcs
 * @date 2021-3-5
 */
@Service
public class DocumentFlowHandleServiceImpl implements DocumentFlowHandleService {

    @Autowired
    private DocumentFlowHandleManager documentFlowHandleManager;
    @Autowired
    private DocumentFlowManager documentFlowManager;
    @Autowired
    private DocumentClient documentClient;
    @Autowired
    private DictClient dictClient;
    @Autowired
    private DocumentCodeRuleClient documentCodeRuleClient;
    @Autowired
    private UserClient userClient;
    @Autowired
    private UserGroupClient userGroupClient;
    @Autowired
    private DocumentFlowNewAndModifyManager documentFlowNewAndModifyManager;

    @Override
    public List<GetDocumentFlowResponse> listDocumentFlowHandle(DocumentFlowHandleQuery query) {
        Integer startIndex = query.getOffset() * query.getRows();
        Integer endIndex = startIndex + query.getRows();
        List<DocumentFlowBO> documentFlowBOList = new ArrayList<>();
        query.setOffset(0);
        query.setRows(Integer.MAX_VALUE);
        List<DocumentFlowHandleBO> documentFlowHandleBOList = documentFlowHandleManager.listDocumentFlowHandle(query);
        //过滤为已经处理过的记录
        documentFlowHandleBOList = documentFlowHandleBOList.stream().filter(d -> d.getResult() > 0).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(documentFlowHandleBOList)) {
            documentFlowBOList = documentFlowManager.listDocumentFlowById(
                    documentFlowHandleBOList.stream().map(DocumentFlowHandleBO::getDocumentFlowId).collect(Collectors.toSet()));
        }
        endIndex = documentFlowBOList.size() < endIndex ? documentFlowBOList.size() : endIndex;
        documentFlowBOList = documentFlowBOList.stream()
                .peek(doc -> doc.setAccessTimeString(CalendarUtils.getDeadlineString(doc.getCreateTime(), LocalDateTime.now())))
                .collect(Collectors.toList());
        documentFlowBOList.sort((m1, m2) -> m2.getUpdateTime().compareTo(m1.getUpdateTime()));
        List<GetDocumentFlowResponse> getDocumentFlowResponses = DocumentFlowConverter.toResponse(documentFlowBOList.subList(startIndex, endIndex));
        //获取自己处理的发行节点
        List<DocumentFlowHandleBO> documentFlowHandleBOS1 = documentFlowHandleManager.listDocumentFlowHandle(DocumentFlowHandleQuery.max()
                .flowType(DocumentFlowConstants.FLOW_TYPE_NEW)
                .handleUserId(UserContextHolder.getUserId())
                .phase(DocumentFlowConstants.PHASE_RELEASE).build());
        Set<Long> collect = documentFlowHandleBOS1.stream().map(e -> e.getDocumentFlowId()).collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(collect)) {
            return getDocumentFlowResponses;
        }
        List<DocumentFlowNewAndModifyBO> documentFlowNewAndModifyList = documentFlowNewAndModifyManager.getDocumentFlowNewAndModifyList(collect);
        Map<Long, DocumentFlowNewAndModifyBO> collect1 = documentFlowNewAndModifyList.stream().collect(Collectors.toMap(e -> e.getDocumentFlowId(), e -> e));
        getDocumentFlowResponses.sort((m1, m2) -> m2.getCreateTime().compareTo(m1.getCreateTime()));
        getDocumentFlowResponses.stream().forEach(e -> {
            if (collect.contains(e.getDocumentFlowId())) {
                e.setDelay(true);
                DocumentFlowNewAndModifyBO documentFlowNewAndModifyBO = collect1.get(e.getDocumentFlowId());
                if (Objects.nonNull(documentFlowNewAndModifyBO)) {
                    e.setEffectDate(documentFlowNewAndModifyBO.getEffectDate());
                }
            }
        });
        userClient.buildByUser(getDocumentFlowResponses,
                getDocumentFlowResponses.stream().map(d -> d.getCreateUserId()).collect(Collectors.toSet()),
                GetDocumentFlowResponse::getCreateUserId,
                (d, userDTO) -> d.setCreateUserName(userDTO.getUserName()));
        return getDocumentFlowResponses;
    }

    @Override
    public int countDocumentFlowHandle(DocumentFlowHandleQuery query) {
//        int i = documentFlowHandleManager.countDocumentFlowHandle(query);
        query.setOffset(0);
        query.setRows(Integer.MAX_VALUE);
        List<DocumentFlowHandleBO> documentFlowHandleBOList = documentFlowHandleManager.listDocumentFlowHandle(query);
        //过滤为已经处理过的记录
        documentFlowHandleBOList = documentFlowHandleBOList.stream().filter(d -> d.getResult() > 0).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(documentFlowHandleBOList)) {
            List<DocumentFlowBO> documentFlowBOS = documentFlowManager.listDocumentFlowById(
                    documentFlowHandleBOList.stream().map(DocumentFlowHandleBO::getDocumentFlowId).collect(Collectors.toSet()));
            return documentFlowBOS.size();
        }
        return 0;
    }


    @Override
    public Result<List<GetDocumentFlowHandleResponse>> listDocumentFlowHandleByPhase(DocumentFlowHandleQuery query) {
        List<DocumentFlowHandleBO> documentFlowHandleBOS = documentFlowHandleManager.listDocumentFlowHandle(query);
        List<GetDocumentFlowHandleResponse> getDocumentFlowHandleResponses = DocumentFlowHandleConverter.toResponse(documentFlowHandleBOS);
        userClient.buildByUser(getDocumentFlowHandleResponses,
                getDocumentFlowHandleResponses.stream().map(e -> e.getHandleUserId()).collect(Collectors.toSet()),
                GetDocumentFlowHandleResponse::getHandleUserId,
                (getDocumentFlowHandleResponse, userDTO) -> getDocumentFlowHandleResponse.setHandleUserName(userDTO.getUserName()));
        return Result.success(getDocumentFlowHandleResponses);
    }

    @Override
    public Result<List<GetDocumentFlowHandleResponse>> listDocumentFlowHandleByDocumentCode(GetDocumentByCodeRequest request) {
        //根据documentCode获取文件
        GetDocumentResponse getDocumentResponse = ResultUtils.get(documentCodeRuleClient.getDocumentByCode(request));
        if (Objects.isNull(getDocumentResponse)) {
            return Result.fail("", "无此文档信息！");
        }
        //根据文件名和文件版本查document_flow
        DocumentFlowBO documentFlow = documentFlowManager.getDocumentFlow(DocumentFlowQuery.one()
                .documentId(getDocumentResponse.getDocumentId())
                .documentVersion(getDocumentResponse.getVersion())
                .documentName(getDocumentResponse.getDocumentName())
                .documentCode(request.getCode()).build());
        if (documentFlow == null) {
            return Result.fail("", "无此流程信息！");
        }
        Long documentFlowId;
        if(!documentFlow.getBatchType().equals(DocumentFlowBatchTypeEnum.UNBATCH.getCode())){
            documentFlowId = documentFlow.getParentDocumentFlowId();
        }else {
            documentFlowId = documentFlow.getDocumentFlowId();
        }
        return listDocumentFlowHandleByPhase(DocumentFlowHandleQuery.builder()
                .documentFlowId(documentFlowId)
                .phase(request.getPhase())
                .build());
    }

    @Override
    public Result<List<DocumentFlowHandleTimeLineResponse>> listDocumentFlowSimpleNodesHandle(GetDocumentFlowSimpleHandlesRequest request) {
        List<DocumentFlowHandleBO> documentFlowHandleBOS = documentFlowHandleManager.listDocumentFlowHandle(
                DocumentFlowHandleQuery.max().documentFlowId(request.getDocumentFlowId()).build());
        List<DocumentFlowHandleTimeLineResponse> documentFlowHandleTimeLineResponses = DocumentFlowHandleConverter.toTimeLineResponse(documentFlowHandleBOS);
        userClient.buildByUser(documentFlowHandleTimeLineResponses,
                documentFlowHandleTimeLineResponses.stream().map(DocumentFlowHandleTimeLineResponse::getHandleUserId).collect(Collectors.toSet()),
                DocumentFlowHandleTimeLineResponse::getHandleUserId,
                (resp, u) -> resp.setHandleUserName(u.getUserName()));
        Collections.sort(documentFlowHandleTimeLineResponses, Comparator.comparing(DocumentFlowHandleTimeLineResponse::getUpdateTime));
        documentFlowHandleTimeLineResponses.forEach(doc -> {
            doc.setTime(CalendarUtils.getDeadlineString(doc.getUpdateTime(), LocalDateTime.now()));
        });
        return Result.success(documentFlowHandleTimeLineResponses);
    }

    @Override
    public List<GetDocumentFlowHandleResponse> listDocumentFlowNodesHandle(GetDocumentFlowSimpleHandlesRequest request) {
        if (Objects.isNull(request.getDocumentFlowId())) {
            return Collections.emptyList();
        }
        DocumentFlowBO documentFlow = documentFlowManager.getDocumentFlow(request.getDocumentFlowId());
        List<DocumentFlowHandleBO> documentFlowHandleBOS = documentFlowHandleManager.listDocumentFlowHandle(
                DocumentFlowHandleQuery.max().documentFlowId(request.getDocumentFlowId()).build());
        if (Objects.isNull(documentFlow) || CollectionUtils.isEmpty(documentFlowHandleBOS)) {
            return Collections.emptyList();
        }
        documentFlowHandleBOS = documentFlowHandleBOS.stream().filter(d -> !Objects.equals(HANDLE_RESULT_CANCEL, d.getResult())).collect(Collectors.toList());
        List<GetDocumentFlowHandleResponse> getDocumentFlowHandleResponses = DocumentFlowHandleConverter.toResponse(documentFlowHandleBOS);
        Result<GetDocumentResponse> document = documentClient.getDocument(GetDocumentRequest.builder().documentId(documentFlow.getDocumentId()).build());
        if (document.getData() != null) {
            getDocumentFlowHandleResponses.forEach(docFlow -> {
                docFlow.setFileExtension(document.getData().getFileExtension());
            });
        }
        getDocumentFlowHandleResponses.forEach(docFlow -> {
            docFlow.setDocumentName(documentFlow.getDocumentName());
            docFlow.setDocumentVersion(documentFlow.getDocumentVersion());
            docFlow.setUrgent(documentFlow.getUrgent());
            docFlow.setLevel(String.valueOf(documentFlow.getDocumentLevel()));
            docFlow.setPhaseName(DocumentFlowConstants.getPhaseName(docFlow.getFlowType(), docFlow.getPhase()));
            docFlow.setCreateTimeString(CalendarUtils.getDeadlineString(docFlow.getCreateTime(), LocalDateTime.now()));
            docFlow.setDocumentProperty(documentFlow.getDocumentProperty());
        });
        userClient.buildByUser(getDocumentFlowHandleResponses,
                getDocumentFlowHandleResponses.stream().map(GetDocumentFlowHandleResponse::getHandleUserId).collect(Collectors.toSet()),
                GetDocumentFlowHandleResponse::getHandleUserId,
                (resp, userDTO) -> resp.setHandleUserName(userDTO.getUserName()));
        userGroupClient.buildByUserGroup(getDocumentFlowHandleResponses,
                getDocumentFlowHandleResponses.stream().map(GetDocumentFlowHandleResponse::getHandleUserGroupId).collect(Collectors.toSet()),
                GetDocumentFlowHandleResponse::getHandleUserGroupId,
                (resp, userGroupDTO) -> resp.setHandleUserGroupName(userGroupDTO.getUserGroupName()));
        getDocumentFlowHandleResponses.sort(Comparator.comparing(GetDocumentFlowHandleResponse::getUpdateTime));
        return getDocumentFlowHandleResponses;
    }

    @Override
    public Result<UserTreeItem> getDrafterUserGroup(GetDocumentFlowSimpleHandlesRequest request) {
        List<DocumentFlowHandleBO> documentFlowHandleBOS = documentFlowHandleManager.listDocumentFlowHandle(DocumentFlowHandleQuery.builder().documentFlowId(request.getDocumentFlowId()).build());
        List<DocumentFlowHandleBO> documentFlowHandleBO = documentFlowHandleBOS.stream().filter(doc -> doc.getPhase().equals(DocumentFlowConstants.PHASE_EDIT)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(documentFlowHandleBO)) {
            return null;
        }
        DocumentFlowHandleBO dfh = documentFlowHandleBO.get(0);
        UserTreeItem t = new UserTreeItem();
        t.setUserId(dfh.getHandleUserGroupId());
        UserGroupDTO userGroup = ResultUtils.get(userGroupClient.getUserGroup(GetUserGroupRequest.builder().userGroupId(dfh.getHandleUserGroupId()).build()));
        t.setUserName(userGroup.getUserGroupName());
        List<UserTreeItem> tree = new ArrayList<>();
        List<UserDTO> userDTOS = ResultUtils.get(userClient.listUserByUserGroup(ListUserGroupByIdsRequest.builder().groupIds(Arrays.asList(dfh.getHandleUserGroupId())).build()));
        userDTOS.forEach(u -> {
            UserTreeItem node = new UserTreeItem();
            node.setUserId(u.getUserId());
            node.setUserName(u.getUserName());
            tree.add(node);
        });
        t.setChildren(tree);
        return Result.success(t);
    }
}
